﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MagicArenaFramework.GameObject.Components;
using MagicArenaXNA.GameObject.Spells.factory;
using MagicArenaXNA.Games;
using MagicArenaXNA.World;
using Networking;
using Microsoft.Xna.Framework.Input;
using MagicArenaXNA.GameObject.Spells.concrete;
using BEPUphysics.Entities;
using MagicArenaFramework.GameObject.Attributes;
using MagicArenaFramework.GameObject.Attributes.Concrete;

namespace MagicArenaXNA.GameObject.Spells
{
    public class SpellBag : GoComposite
    {
        public delegate void OnSpellChange(object sender, SpellBase[] newSpells);

        private SpellBase.SpellSchool _CurrentSchool;
        public SpellBase.SpellSchool CurrentSchool
        {
            get { return _CurrentSchool; }
            set
            {
                _CurrentSchool = value;
                if(SpellChange!=null)SpellChange(this, Spells(value));
            }
        }
        public event OnSpellChange SpellChange;

        private ISpellFactory SpellFactory;
        private Targetter Targetter;

        private ScalarAttributeHolder Attributes;

        Dictionary<SpellBase.SpellSchool, List<SpellBase>> SpellDict = new Dictionary<SpellBase.SpellSchool, List<SpellBase>>(4);
        
        public SpellBag(BepuGame game, BepuWorld world, SimpleGameClient client, Targetter targetter)
        {
            BasicSpellFactory fact = new BasicSpellFactory(client, world, game);
            AddChild(fact);
            SpellFactory = fact;
            InitDict();
            CurrentSchool = SpellBase.SpellSchool.Red;
            Targetter = targetter;
            

            //Set delegate
            this.UpdateDel = MyUpdate;
        }

        #region

        #endregion

        void InitDict()
        {
            List<SpellBase> red = new List<SpellBase>(4);
            red.Add(new SpellFireballOne());
            AddChild(red[0]);
            SpellDict.Add(SpellBase.SpellSchool.Red, red);
            SpellDict.Add(SpellBase.SpellSchool.Blue, new List<SpellBase>(1));
            SpellDict.Add(SpellBase.SpellSchool.Brown, new List<SpellBase>(1));
            SpellDict.Add(SpellBase.SpellSchool.Green, new List<SpellBase>(1));
        }

        public SpellBase[] Spells(SpellBase.SpellSchool school)
        {
            List<SpellBase> list;
            SpellDict.TryGetValue(school, out list);
            return list.ToArray();
        }

        #region GoComponent methods
        public override void RegisterSelf(GoComposite parent)
        {
            GoComponent comp;
            if (parent.GetChild(typeof(ScalarAttributeHolder), out comp))
            {
                Attributes = comp as ScalarAttributeHolder;
            }
            else
            {
                throw new ArgumentException("Spell bag cannot be added to a composite which does not already have attributes");
            }
            base.RegisterSelf(parent);
        }
    
        private KeyboardState prevKeyState = Keyboard.GetState();
        void MyUpdate(float dt)
        {
            KeyboardState keyState = Keyboard.GetState();
            List<SpellBase> spells;
            SpellBase spell=null;
            if (SpellDict.TryGetValue(CurrentSchool, out spells))
            {
                //Check to see if any of the spells have been cast
                if (keyState.IsKeyDown(Keys.D1) && prevKeyState.IsKeyUp(Keys.D1))
                {
                    spell = spells[0];
                }
                else if (keyState.IsKeyDown(Keys.D2) && prevKeyState.IsKeyUp(Keys.D2))
                {
                    spell = spells[1];
                }
                else if (keyState.IsKeyDown(Keys.D3) && prevKeyState.IsKeyUp(Keys.D3))
                {
                    spell = spells[2];
                }
                else if (keyState.IsKeyDown(Keys.D4) && prevKeyState.IsKeyUp(Keys.D4))
                {
                    spell = spells[3];
                }
                CastSpell(spell);
            }
            prevKeyState = keyState;
        }
        #endregion

        void CastSpell(SpellBase spell)
        {
            float mana;
            // If the spell isn't null, isn't cooling down and we have enough mana, cast it
            if (spell != null && spell.CurrentCooldownPercent==0 && Attributes.ValueFor(CurManaAttribute.CurManaFamily, out mana) && spell.ManaCost<mana)
            {
                // Create the physical entity
                bool casted = false;
                if (spell.Target == SpellBase.SpellTarget.Other)
                {
                    if (Targetter.CanAttack)
                    {
                        SpellFactory.CreateSpell(spell, Targetter.Self, Targetter.CurTargetEntity);
                        casted = true;
                    }
                }
                else
                {
                    SpellFactory.CreateSpell(spell, Targetter.Self, Targetter.Self);
                    casted = true;
                }
                // Update values for this spell
                if (casted)
                {
                    // Decrease mana
                    mana -= spell.ManaCost;
                    Attributes.AddUpdateValue(CurManaAttribute.CurManaFamily, mana);

                    // Set cooldown time for spell
                    spell.CurrentCooldown = spell.CastCooldown;

                    //TODO update to include cast time, some things will need to be reordered for that to work
                }

            }
        }
    }
}
